package cn.demoncat.util.lang;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 反射工具类
 *
 * @author 延晓磊
 *
 * @since 2017年7月10日
 */
public class ReflectUtil {
 
	/**
	 * Map转换为对象
	 * 
	 * @param map		数据源
	 * @param clazz		对象类型
	 * 
	 * @return obj	赋值实例字段：包含继承字段，不包含final字段
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <T>T toObj(Map<String, ?> map, Class<T> clazz) {
		return toObj(map,clazz, false, false);
	}

	/**
	 * Map转换为对象
	 * 
	 * @param map				数据源（排除null字段，保留类的初始字段）
	 * @param clazz				对象类型
	 * @param excludeNull		是否排除数据源的null值：true Map值为null时忽略
	 * @param excludeNotNull	是否排除目标对象的非null值：true 目标对象的字段非null时忽略
	 * 
	 * @return obj	赋值实例字段：包含继承字段，不包含final字段
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <T>T toObj(Map<String, ?> map, Class<T> clazz, boolean excludeNull, boolean excludeNotNull) {
		return merge(map, ReflectClassUtil.instance(clazz), excludeNull, excludeNotNull);
	}
	
	/**
	 * 将Map的值赋给对象
	 * 
	 * @param map	数据源：忽略null值
	 * @param obj	目标对象：包含继承字段，不包含final字段
	 * 
	 * @return obj	赋值实例字段：将map的非null值拷贝到对象
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <T>T copy(Map<String, ?> map, T obj) {
		return merge(map, obj, true, false);
	}
	
	/**
	 * 将Map的值赋给对象
	 * 
	 * @param map			数据源
	 * @param obj			目标对象：包含继承字段，不包含final字段
	 * @param excludeNull	是否排除数据源的null值：true Map值为null时忽略
	 *  
	 * @return obj	赋值实例字段：将map的值拷贝到对象
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <T>T copy(Map<String, ?> map, T obj, boolean excludeNull) {
		return merge(map, obj, excludeNull, false);
	}
	
	/**
	 * 将Map的值赋给对象
	 * 
	 * @param map	数据源：忽略null值
	 * @param obj	目标对象：包含继承字段，不包含final字段，忽略非null字段
	 * 
	 * @return obj	赋值实例字段：合并map和obj的非null值
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <T>T merge(Map<String, ?> map, T obj) {
		return merge(map, obj, true, true);
	}
	
 
	/**
	 * 将Map的值赋给对象
	 * 
	 * @param map				数据源
	 * @param obj				目标对象：包含继承字段，不包含final字段
	 * @param excludeNull		是否排除数据源的null值：true Map值为null时忽略
	 * @param excludeNotNull	是否排除目标对象的非null值：true 目标对象的字段非null时忽略
	 * 
	 * @return obj	赋值实例字段
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <T>T merge(Map<String, ?> map, T obj, boolean excludeNull, boolean excludeNotNull) {
		// 获取实例字段
		Object fv;
		for (Field field : ReflectFieldUtil.getInstanceWritableFields(obj.getClass())) {
			// 数据源非空
			fv = map.get(field.getName());
			if (excludeNull && fv == null) {
				continue;
			}
			// 设置字段值
			ReflectFieldUtil.set(obj, field, fv, excludeNotNull);
		}
		return obj;
	}
	
	/**
	 * 对象转换为Map
	 * 
	 * @param o	对象
	 * 
	 * @return	Map 所有实例字段，包含继承字段
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static Map<String, Object> toMap(Object o) {
		Map<String, Object> map = new HashMap<>();
		// 获取实例字段
		for (Field field : ReflectFieldUtil.getInstanceFields(o.getClass())) {
			// 转换
			map.put(field.getName(), ReflectFieldUtil.get(o, field));
		}
		return map;
	}

	/**
	 * 对象转换为Map
	 * 
	 * @param o	对象
	 * @param excludeNull	是否排除数据源的null值：true 字段值为null时忽略
	 * 
	 * @return	Map 所有实例字段，包含继承字段
	 * 
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static Map<String, Object> toMap(Object o, boolean excludeNull) {
		Map<String, Object> map = new HashMap<>();
		// 获取实例字段
		Object fv;
		for (Field field : ReflectFieldUtil.getInstanceFields(o.getClass())) {
			// 转换
			fv = ReflectFieldUtil.get(o, field);
			if (!excludeNull || fv != null) {
				map.put(field.getName(), fv);
			}
		}
		return map;
	}
	
	/**
	 * 对象转换为Map
	 * 
	 * @param o	对象
	 * 
	 * @return	Map 所有实例字段，包含继承字段
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static Map<String, String> toStrMap(Object o) {
		Map<String, String> map = new HashMap<>();
		// 获取实例字段
		for (Field field : ReflectFieldUtil.getInstanceFields(o.getClass())) {
			// 转换
			map.put(field.getName(), StringUtil.toString(ReflectFieldUtil.get(o, field)));
		}
		return map;
	}
	
	/**
	 * 对象转换为Map
	 * 
	 * @param o	对象
	 * @param excludeNull	是否排除数据源的null/""值：true 字段值为null/""时忽略
	 * 
	 * @return	Map 所有实例字段，包含继承字段
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static Map<String, String> toStrMap(Object o, boolean excludeNull) {
		Map<String, String> map = new HashMap<>();
		// 获取实例字段
		String fv;
		for (Field field : ReflectFieldUtil.getInstanceFields(o.getClass())) {
			// 转换
			fv = StringUtil.toString(ReflectFieldUtil.get(o, field));
			if (!excludeNull || StringUtils.isNotBlank(fv)) {
				map.put(field.getName(), fv);
			}
		}
		return map;
	}

	/**
	 * 克隆（通过JSON转换，忽略类型）
	 * 
	 * @param o
	 * @param clazz
	 * @param <T>
	 * @return
	 * 
	 * @author 延晓磊
	 * @since 2023年04月10日
	 */
	public static <T>T clone(Object o, Class<T> clazz){
		return JsonUtil.parse(JsonUtil.toString(o), clazz);
	}
	
	/**
	 * 克隆
	 * <pre>
	 * 1、包含继承、私有字段
	 * 2、忽略源对象的static,serialVersionUID,null字段
	 * </pre> 
	 * @param o	源对象
	 * 
	 * @return	新对象
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月25日
	 */
	@SuppressWarnings("unchecked")
	public static <T>T clone(T o) {
		return (T) merge(o, ReflectClassUtil.instance(o.getClass()), false, false);
	}

	/**
	 * 深度克隆
	 *
	 * @param o
	 * @param <T>
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T>T cloneDeep(T o){
		return (T)BeanUtil.clone(o);
	}

	/**
	 * 克隆列表
	 *
	 * @param os
	 * @param clazz	返回类型
	 * @return
	 */
	public static <T>List<T> cloneList(List<T> os, Class<T> clazz){
		return JsonUtil.parseList(JsonUtil.toString(os), clazz);
	}

	/**
	 * 将源对象的实例字段合并到新对象（忽略原对象的null字段）
	 * <pre>
	 * 1、包含继承、私有字段
	 * 2、忽略源对象的static,serialVersionUID,null字段
	 * 3、忽略新对象的static,final,serialVersionUID,类型不匹配字段
	 * </pre>
	 * 
	 * @param o		源对象，忽略null字段
	 * @param n		新对象，不保留非null字段
	 * 
	 * @return 新对象，将原对象的非null字段拷贝到新对象
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <O,N>N copy(O o, N n) {
		return copy(o, n, true);
	}

	/**
	 * 深拷贝
	 *
	 * @param o		源对象
	 * @param n		新对象
	 *
	 * @return 新对象
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <O,N>N copyDeep(O o, N n) {
		BeanUtil.copy(o, n);
		return n;
	}

	/**
	 * 将源对象的实例字段拷贝到新对象
	 * <pre>
	 * 1、包含继承、私有字段
	 * 2、忽略源对象的static,serialVersionUID字段
	 * 3、忽略新对象的static,final,serialVersionUID,类型不匹配字段
	 * </pre>
	 * 
	 * @param o		源对象
	 * @param n		新对象，不保留非null字段
	 * @param excludeNull	是否排除原对象的null值：true 原对象字段为null时忽略
	 * 
	 * @return 新对象
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <O,N>N copy(O o, N n, boolean excludeNull) {
		return merge(o, n, excludeNull, false);
	}
	
	/**
	 * 将源对象的非空实例字段合并到新对象（忽略原对象的null字段，忽略新对象的非null字段）
	 * <pre>
	 * 1、包含继承、私有字段
	 * 2、忽略源对象的static,serialVersionUID,null字段
	 * 3、忽略新对象的static,final,serialVersionUID,类型不匹配字段,非null字段
	 * </pre>
	 * 
	 * @param o		源对象，忽略null字段
	 * @param n		新对象，保留非null字段
	 * 
	 * @return 新对象，合并两个对象中的非null字段
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <O,N>N merge(O o, N n) {
		return merge(o, n, true, true);
	}
	
	/**
	 * 将源对象的实例字段合并到新对象
	 * <pre>
	 * 1、包含继承、私有字段
	 * 2、忽略源对象的static,serialVersionUID字段
	 * 3、忽略新对象的static,final,serialVersionUID,类型不匹配字段（继承关系为不匹配）
	 * </pre>
	 * 
	 * @param o			源对象
	 * @param n			新对象
	 * @param excludeNull		是否排除原对象的null值：true 原对象字段为null时忽略
	 * @param excludeNotNull	是否排除新对象的非null值：true 新对象的字段非null时忽略
	 * @return 
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月25日
	 */
	public static <O,N>N merge(O o, N n, boolean excludeNull, boolean excludeNotNull) {
		// 获取源对象的所有实例字段
		List<Field> ofs = ReflectFieldUtil.getInstanceFields(o.getClass());
		Object fv;
		for (Field of : ofs) {
			// 获取原对象的字段值
			fv = ReflectFieldUtil.get(o, of);
			// 忽略原对象的null值
			if (excludeNull && fv == null) {
				continue;
			}
			// 设置新对象的字段
			ReflectFieldUtil.set(n, of.getName(), fv, excludeNotNull);
		}
		return n;
	}
	

}
